{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "[![image](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://demo.leafmap.org/lab/index.html?path=notebooks/92_maplibre.ipynb)\n",
    "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/notebooks/92_maplibre.ipynb)\n",
    "[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n",
    "\n",
    "**Creating 3D maps with MapLibre**\n",
    "\n",
    "The notebook demonstrates how to create 3D maps using the [MapLibre](https://github.com/eodaGmbH/py-maplibregl) Python package. The examples shown in this notebook are based on the [MapLibre documentation](https://eodagmbh.github.io/py-maplibregl/examples/vancouver_blocks/). Credits to the original authors at [eoda GmbH](https://www.eoda.de/en/).\n",
    "\n",
    "## Installation\n",
    "\n",
    "Uncomment the following line to install [leafmap](https://leafmap.org) if needed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# %pip install \"leafmap[maplibre]\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2",
   "metadata": {},
   "source": [
    "## Import libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import leafmap.maplibregl as leafmap"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4",
   "metadata": {},
   "source": [
    "## Create maps\n",
    "\n",
    "Create an interactive map by specifying map center [lon, lat], zoom level, pitch, and bearing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(center=[-100, 40], zoom=3, pitch=0, bearing=0)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/8ITaEZa.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7",
   "metadata": {},
   "source": [
    "To customize the basemap, you can specify the `style` parameter. It can be an URL or a string, such as `dark-matter`, `positron`, `voyager`, `demotiles`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(style=\"positron\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/9fImW21.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10",
   "metadata": {},
   "source": [
    "To create a map with a background color, use `style=\"background-<COLOR>\"`, such as `background-lightgray` and `background-green`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(style=\"background-lightgray\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/xFeDTkE.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13",
   "metadata": {},
   "source": [
    "Alternatively, you can provide a URL to a vector style."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14",
   "metadata": {},
   "outputs": [],
   "source": [
    "style = \"https://demotiles.maplibre.org/style.json\"\n",
    "m = leafmap.Map(style=style)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/yaZYrr1.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16",
   "metadata": {},
   "source": [
    "## Add controls\n",
    "\n",
    "The control to add to the map. Can be one of the following: `scale`, `fullscreen`, `geolocate`, `navigation`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map()\n",
    "m.add_control(\"geolocate\", position=\"top-left\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/7LS5WAk.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19",
   "metadata": {},
   "source": [
    "## Add basemaps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map()\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "21",
   "metadata": {},
   "outputs": [],
   "source": [
    "m.add_basemap()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map()\n",
    "m.add_basemap(\"OpenTopoMap\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/MRRw1MW.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24",
   "metadata": {},
   "outputs": [],
   "source": [
    "m.add_basemap(\"Esri.WorldImagery\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25",
   "metadata": {},
   "source": [
    "## XYZ tile layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "26",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map()\n",
    "url = \"https://tile.openstreetmap.org/{z}/{x}/{y}.png\"\n",
    "m.add_tile_layer(\n",
    "    url, name=\"OpenStreetMap\", attribution=\"OpenStreetMap\", opacity=1.0, visible=True\n",
    ")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/V9wmsjl.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28",
   "metadata": {},
   "source": [
    "## WMS layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(center=[-100, 40], zoom=3)\n",
    "m.add_basemap(\"Esri.WorldImagery\")\n",
    "url = \"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2021_Land_Cover_L48/wms\"\n",
    "layers = \"NLCD_2021_Land_Cover_L48\"\n",
    "m.add_wms_layer(url, layers=layers, name=\"NLCD\", opacity=0.8)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/xcZ4VKv.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31",
   "metadata": {},
   "source": [
    "## COG layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "32",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map()\n",
    "url = (\n",
    "    \"https://github.com/opengeos/datasets/releases/download/raster/Libya-2023-07-01.tif\"\n",
    ")\n",
    "m.add_cog_layer(url, name=\"COG\", attribution=\"Maxar\", fit_bounds=True)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/ApGhjDp.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34",
   "metadata": {},
   "source": [
    "## STAC layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "35",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map()\n",
    "url = \"https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json\"\n",
    "m.add_stac_layer(url, bands=[\"B4\", \"B3\", \"B2\"], name=\"SPOT\", vmin=0, vmax=150)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/RJAhsV5.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37",
   "metadata": {},
   "source": [
    "## Local raster"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = \"https://github.com/opengeos/datasets/releases/download/raster/srtm90.tif\"\n",
    "filepath = \"srtm90.tif\"\n",
    "leafmap.download_file(url, filepath)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map()\n",
    "m.add_raster(filepath, colormap=\"terrain\", name=\"DEM\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/pMcuQAp.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41",
   "metadata": {},
   "source": [
    "## Vancouver Property Value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(\n",
    "    center=[-123.13, 49.254], zoom=11, style=\"dark-matter\", pitch=45, bearing=0\n",
    ")\n",
    "url = \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/geojson/vancouver-blocks.json\"\n",
    "paint_line = {\n",
    "    \"line-color\": \"white\",\n",
    "    \"line-width\": 2,\n",
    "}\n",
    "paint_fill = {\n",
    "    \"fill-extrusion-color\": {\n",
    "        \"property\": \"valuePerSqm\",\n",
    "        \"stops\": [\n",
    "            [0, \"grey\"],\n",
    "            [1000, \"yellow\"],\n",
    "            [5000, \"orange\"],\n",
    "            [10000, \"darkred\"],\n",
    "            [50000, \"lightblue\"],\n",
    "        ],\n",
    "    },\n",
    "    \"fill-extrusion-height\": [\"*\", 10, [\"sqrt\", [\"get\", \"valuePerSqm\"]]],\n",
    "    \"fill-extrusion-opacity\": 0.9,\n",
    "}\n",
    "m.add_geojson(url, layer_type=\"line\", paint=paint_line, name=\"blocks-line\")\n",
    "m.add_geojson(url, layer_type=\"fill-extrusion\", paint=paint_fill, name=\"blocks-fill\")\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43",
   "metadata": {},
   "outputs": [],
   "source": [
    "m.layer_interact()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/IZXfgSz.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45",
   "metadata": {},
   "source": [
    "## Earthquake Clusters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "46",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(style=\"positron\")\n",
    "\n",
    "data = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n",
    "source_args = {\n",
    "    \"cluster\": True,\n",
    "    \"cluster_radius\": 50,\n",
    "    \"cluster_min_points\": 2,\n",
    "    \"cluster_max_zoom\": 14,\n",
    "    \"cluster_properties\": {\n",
    "        \"maxMag\": [\"max\", [\"get\", \"mag\"]],\n",
    "        \"minMag\": [\"min\", [\"get\", \"mag\"]],\n",
    "    },\n",
    "}\n",
    "\n",
    "m.add_geojson(\n",
    "    data,\n",
    "    layer_type=\"circle\",\n",
    "    name=\"earthquake-circles\",\n",
    "    filter=[\"!\", [\"has\", \"point_count\"]],\n",
    "    paint={\"circle-color\": \"darkblue\"},\n",
    "    source_args=source_args,\n",
    ")\n",
    "\n",
    "m.add_geojson(\n",
    "    data,\n",
    "    layer_type=\"circle\",\n",
    "    name=\"earthquake-clusters\",\n",
    "    filter=[\"has\", \"point_count\"],\n",
    "    paint={\n",
    "        \"circle-color\": [\n",
    "            \"step\",\n",
    "            [\"get\", \"point_count\"],\n",
    "            \"#51bbd6\",\n",
    "            100,\n",
    "            \"#f1f075\",\n",
    "            750,\n",
    "            \"#f28cb1\",\n",
    "        ],\n",
    "        \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 20, 100, 30, 750, 40],\n",
    "    },\n",
    "    source_args=source_args,\n",
    ")\n",
    "\n",
    "m.add_geojson(\n",
    "    data,\n",
    "    layer_type=\"symbol\",\n",
    "    name=\"earthquake-labels\",\n",
    "    filter=[\"has\", \"point_count\"],\n",
    "    layout={\n",
    "        \"text-field\": [\"get\", \"point_count_abbreviated\"],\n",
    "        \"text-size\": 12,\n",
    "    },\n",
    "    source_args=source_args,\n",
    ")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/vge4jF4.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48",
   "metadata": {},
   "source": [
    "## Airport Markers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49",
   "metadata": {},
   "outputs": [],
   "source": [
    "from maplibre.controls import Marker, MarkerOptions, Popup, PopupOptions\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(style=\"positron\")\n",
    "\n",
    "url = \"https://github.com/visgl/deck.gl-data/raw/master/examples/line/airports.json\"\n",
    "data = leafmap.pandas_to_geojson(\n",
    "    url, \"coordinates\", properties=[\"type\", \"name\", \"abbrev\"]\n",
    ")\n",
    "\n",
    "m.add_geojson(\n",
    "    data,\n",
    "    name=\"Airports\",\n",
    "    layer_type=\"circle\",\n",
    "    paint={\n",
    "        \"circle-color\": [\n",
    "            \"match\",\n",
    "            [\"get\", \"type\"],\n",
    "            \"mid\",\n",
    "            \"darkred\",\n",
    "            \"major\",\n",
    "            \"darkgreen\",\n",
    "            \"darkblue\",\n",
    "        ],\n",
    "        \"circle_radius\": 10,\n",
    "        \"circle-opacity\": 0.3,\n",
    "    },\n",
    ")\n",
    "\n",
    "\n",
    "def get_color(airport_type: str) -> str:\n",
    "    color = \"darkblue\"\n",
    "    if airport_type == \"mid\":\n",
    "        color = \"darkred\"\n",
    "    elif airport_type == \"major\":\n",
    "        color = \"darkgreen\"\n",
    "\n",
    "    return color\n",
    "\n",
    "\n",
    "airports_data = pd.read_json(url)\n",
    "popup_options = PopupOptions(close_button=False)\n",
    "\n",
    "for _, r in airports_data.iterrows():\n",
    "    m.add_marker(\n",
    "        lng_lat=r[\"coordinates\"],\n",
    "        options=MarkerOptions(color=get_color(r[\"type\"])),\n",
    "        popup=Popup(\n",
    "            text=r[\"name\"],\n",
    "            options=popup_options,\n",
    "        ),\n",
    "    )\n",
    "\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/q7nN1PW.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52",
   "metadata": {},
   "source": [
    "## 3D Indoor Mapping"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(\n",
    "    center=(-87.61694, 41.86625), zoom=17, pitch=40, bearing=20, style=\"positron\"\n",
    ")\n",
    "m.add_basemap(\"OpenStreetMap.Mapnik\")\n",
    "data = \"https://maplibre.org/maplibre-gl-js/docs/assets/indoor-3d-map.geojson\"\n",
    "m.add_geojson(\n",
    "    data,\n",
    "    layer_type=\"fill-extrusion\",\n",
    "    name=\"floorplan\",\n",
    "    paint={\n",
    "        \"fill-extrusion-color\": [\"get\", \"color\"],\n",
    "        \"fill-extrusion-height\": [\"get\", \"height\"],\n",
    "        \"fill-extrusion-base\": [\"get\", \"base_height\"],\n",
    "        \"fill-extrusion-opacity\": 0.5,\n",
    "    },\n",
    ")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/dteQlQC.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55",
   "metadata": {},
   "source": [
    "## Custom Basemap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56",
   "metadata": {},
   "outputs": [],
   "source": [
    "import leafmap.maplibregl as leafmap\n",
    "from maplibre.basemaps import construct_basemap_style\n",
    "from maplibre import Layer, LayerType, Map, MapOptions\n",
    "from maplibre.sources import GeoJSONSource\n",
    "\n",
    "\n",
    "bg_layer = Layer(\n",
    "    type=LayerType.BACKGROUND,\n",
    "    id=\"background\",\n",
    "    source=None,\n",
    "    paint={\"background-color\": \"darkblue\", \"background-opacity\": 0.8},\n",
    ")\n",
    "\n",
    "countries_source = GeoJSONSource(\n",
    "    data=\"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_0_countries.geojson\"\n",
    ")\n",
    "\n",
    "lines_layer = Layer(\n",
    "    type=LayerType.LINE,\n",
    "    source=\"countries\",\n",
    "    paint={\"line-color\": \"white\", \"line-width\": 1.5},\n",
    ")\n",
    "\n",
    "polygons_layer = Layer(\n",
    "    type=LayerType.FILL,\n",
    "    source=\"countries\",\n",
    "    paint={\"fill-color\": \"darkred\", \"fill-opacity\": 0.8},\n",
    ")\n",
    "\n",
    "custom_basemap = construct_basemap_style(\n",
    "    layers=[bg_layer, polygons_layer, lines_layer],\n",
    "    sources={\"countries\": countries_source},\n",
    ")\n",
    "\n",
    "\n",
    "m = leafmap.Map(style=custom_basemap)\n",
    "data = \"https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson\"\n",
    "m.add_geojson(\n",
    "    data,\n",
    "    layer_type=\"circle\",\n",
    "    name=\"earthquakes\",\n",
    "    paint={\"circle-color\": \"yellow\", \"circle-radius\": 5},\n",
    ")\n",
    "m.add_popup(\"earthquakes\", \"mag\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "57",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/Bn9Kwje.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58",
   "metadata": {},
   "source": [
    "## H3 Grid UK Road Safety"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import h3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "60",
   "metadata": {},
   "outputs": [],
   "source": [
    "RESOLUTION = 7\n",
    "COLORS = (\n",
    "    \"lightblue\",\n",
    "    \"turquoise\",\n",
    "    \"lightgreen\",\n",
    "    \"yellow\",\n",
    "    \"orange\",\n",
    "    \"darkred\",\n",
    ")\n",
    "\n",
    "road_safety = pd.read_csv(\n",
    "    \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv\"\n",
    ").dropna()\n",
    "\n",
    "\n",
    "def create_h3_grid(res=RESOLUTION) -> dict:\n",
    "    road_safety[\"h3\"] = road_safety.apply(\n",
    "        lambda x: h3.geo_to_h3(x[\"lat\"], x[\"lng\"], resolution=res), axis=1\n",
    "    )\n",
    "    df = road_safety.groupby(\"h3\").h3.agg(\"count\").to_frame(\"count\").reset_index()\n",
    "    df[\"hexagon\"] = df.apply(\n",
    "        lambda x: [h3.h3_to_geo_boundary(x[\"h3\"], geo_json=True)], axis=1\n",
    "    )\n",
    "    df[\"color\"] = pd.cut(\n",
    "        df[\"count\"],\n",
    "        bins=len(COLORS),\n",
    "        labels=COLORS,\n",
    "    )\n",
    "    return leafmap.pandas_to_geojson(\n",
    "        df, \"hexagon\", geometry_type=\"Polygon\", properties=[\"count\", \"color\"]\n",
    "    )\n",
    "\n",
    "\n",
    "m = leafmap.Map(\n",
    "    center=(-1.415727, 52.232395),\n",
    "    zoom=7,\n",
    "    pitch=40,\n",
    "    bearing=-27,\n",
    ")\n",
    "try:\n",
    "    data = create_h3_grid()\n",
    "    m.add_geojson(\n",
    "        data,\n",
    "        layer_type=\"fill-extrusion\",\n",
    "        paint={\n",
    "            \"fill-extrusion-color\": [\"get\", \"color\"],\n",
    "            \"fill-extrusion-opacity\": 0.7,\n",
    "            \"fill-extrusion-height\": [\"*\", 100, [\"get\", \"count\"]],\n",
    "        },\n",
    "    )\n",
    "except:\n",
    "    pass\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "61",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/DYWmj5y.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62",
   "metadata": {},
   "source": [
    "## Deck.GL Layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(\n",
    "    style=\"positron\",\n",
    "    center=(-122.4, 37.74),\n",
    "    zoom=12,\n",
    "    pitch=40,\n",
    ")\n",
    "deck_grid_layer = {\n",
    "    \"@@type\": \"GridLayer\",\n",
    "    \"id\": \"GridLayer\",\n",
    "    \"data\": \"https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json\",\n",
    "    \"extruded\": True,\n",
    "    \"getPosition\": \"@@=COORDINATES\",\n",
    "    \"getColorWeight\": \"@@=SPACES\",\n",
    "    \"getElevationWeight\": \"@@=SPACES\",\n",
    "    \"elevationScale\": 4,\n",
    "    \"cellSize\": 200,\n",
    "    \"pickable\": True,\n",
    "}\n",
    "\n",
    "m.add_deck_layers([deck_grid_layer], tooltip=\"Number of points: {{ count }}\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/xBVdT2u.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "65",
   "metadata": {},
   "source": [
    "## Multiple Deck.GL Layers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "66",
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = requests.get(\n",
    "    \"https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson\"\n",
    ").json()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(\n",
    "    style=\"positron\",\n",
    "    center=(0.45, 51.47),\n",
    "    zoom=4,\n",
    "    pitch=30,\n",
    ")\n",
    "deck_geojson_layer = {\n",
    "    \"@@type\": \"GeoJsonLayer\",\n",
    "    \"id\": \"airports\",\n",
    "    \"data\": data,\n",
    "    \"filled\": True,\n",
    "    \"pointRadiusMinPixels\": 2,\n",
    "    \"pointRadiusScale\": 2000,\n",
    "    \"getPointRadius\": \"@@=11 - properties.scalerank\",\n",
    "    \"getFillColor\": [200, 0, 80, 180],\n",
    "    \"autoHighlight\": True,\n",
    "    \"pickable\": True,\n",
    "}\n",
    "\n",
    "deck_arc_layer = {\n",
    "    \"@@type\": \"ArcLayer\",\n",
    "    \"id\": \"arcs\",\n",
    "    \"data\": [\n",
    "        feature\n",
    "        for feature in data[\"features\"]\n",
    "        if feature[\"properties\"][\"scalerank\"] < 4\n",
    "    ],\n",
    "    \"getSourcePosition\": [-0.4531566, 51.4709959],  # London\n",
    "    \"getTargetPosition\": \"@@=geometry.coordinates\",\n",
    "    \"getSourceColor\": [0, 128, 200],\n",
    "    \"getTargetColor\": [200, 0, 80],\n",
    "    \"getWidth\": 2,\n",
    "    \"pickable\": True,\n",
    "}\n",
    "\n",
    "m.add_deck_layers(\n",
    "    [deck_geojson_layer, deck_arc_layer],\n",
    "    tooltip={\n",
    "        \"airports\": \"{{ &properties.name }}\",\n",
    "        \"arcs\": \"gps_code: {{ properties.gps_code }}\",\n",
    "    },\n",
    ")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/eFc4IbZ.png)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
